/*
 * Copyright (c) 2023 Cshoo Org. All Rights Reserved.
 */

package org.cshoo.tattoo.authorize.domain.service;

import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.IteratorUtils;
import org.cshoo.tattoo.authorize.domain.bo.FrontPermissionBo;
import org.cshoo.tattoo.authorize.domain.constant.FrontPermissionType;
import org.cshoo.tattoo.authorize.domain.po.App;
import org.cshoo.tattoo.authorize.domain.po.Button;
import org.cshoo.tattoo.authorize.domain.po.Menu;
import org.cshoo.tattoo.authorize.domain.po.Role;
import org.cshoo.tattoo.authorize.domain.repository.*;
import org.cshoo.tattoo.embed.infra.utils.AuditFieldsUtils;
import org.cshoo.tattoo.embed.infra.utils.UserUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author 杨翼
 * @since 1.0
 */
@Service
@Slf4j
public class AppService {

    @Resource
    private IAppRepository appRepository;

    @Resource
    private IRoleRepository roleRepository;

    @Resource
    private IMenuRepository menuRepository;

    @Resource
    private IButtonRepository buttonRepository;

    /**
     * 查询当前用户的前端权限信息
     * 包括菜单按钮
     *
     * @param appCode 编号
     * @return 权限信息
     */
    public List<FrontPermissionBo> queryCurrentUserFrontPermissions(String appCode) {
        List<FrontPermissionBo> result = Lists.newArrayList();
        App app = appRepository.findAppByCode(appCode);
        Long userId = UserUtils.getUser().getId();
        List<Role> roles = roleRepository.findRolesByUserId(userId);
        List<Long> roleIds = roles.stream().map(Role::getId).distinct().collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(roleIds)) {
            List<Menu> menus = menuRepository.findByAppIdAndRoleIds(app.getId(), roleIds);
            List<Button> buttons = buttonRepository.findByRoleIds(roleIds);
            menus.stream().filter(men -> Objects.isNull(men.getParentId())).forEach(men -> result.add(recursionBuildFrontPermissionBo(men, menus, buttons)));
        }
        return result;
    }

    /**
     * 使用递归的方式组装前端权限bo对象
     *
     * @param currentMenu 菜单
     * @param menus       菜单列表
     * @param buttons     按钮列表
     * @return 前端权限bo对象
     */
    private FrontPermissionBo recursionBuildFrontPermissionBo(Menu currentMenu, List<Menu> menus, List<Button> buttons) {
        if (Objects.isNull(currentMenu)) {
            return null;
        }
        FrontPermissionBo frontPermissionBo = new FrontPermissionBo();
        frontPermissionBo.setType(FrontPermissionType.MENU.getValue());
        BeanUtils.copyProperties(currentMenu, frontPermissionBo);
        frontPermissionBo.setChildren(Lists.newArrayList());
        Long parentId = currentMenu.getId();
        menus.stream()
                .filter(men -> Objects.equals(men.getParentId(), parentId))
                .forEach(men ->
                        frontPermissionBo.getChildren().add(recursionBuildFrontPermissionBo(men, menus, buttons))
                );
        buttons.forEach(btn -> {
            FrontPermissionBo buttonPermission = new FrontPermissionBo();
            buttonPermission.setType(FrontPermissionType.BUTTON.getValue());
            BeanUtils.copyProperties(btn, buttonPermission);
            frontPermissionBo.getChildren().add(buttonPermission);
        });
        return frontPermissionBo;
    }

    /**
     * 判断此编号是否存在
     *
     * @param code app编号
     * @return 判断结果
     */
    public boolean checkAppCodeExists(String code) {
        App app = appRepository.findAppByCode(code);
        log.info("app:{}", app);
        return Objects.nonNull(app);
    }

    /**
     * 添加一个app
     *
     * @param app app
     */
    public void addApp(App app) {
        log.info("app:{}", app);
        AuditFieldsUtils.setAddAuditFields(app);
        appRepository.save(app);
    }

    /**
     * 修改app，这里修改app信息的name,uri,description字段
     *
     * @param app app
     */
    public void updateApp(App app) {
        log.info("app:{}", app);
        AuditFieldsUtils.setUpdateAuditFields(app);
        appRepository.updateApp(app);
    }

    /**
     * 删除app
     *
     * @param id id
     */
    public void deleteApp(Long id) {
        log.info("id:{}", id);
        appRepository.deleteById(id);
    }

    /**
     * 查询app
     *
     * @return app列表
     */
    @SuppressWarnings("unchecked")
    public List<App> findAllApp() {
        Iterable<App> apps = appRepository.findAll();
        return IteratorUtils.toList(apps.iterator());
    }

}
